package umacis.lwuitcomponent;

import com.sun.lwuit.Command;
import com.sun.lwuit.Component;
import com.sun.lwuit.Display;
import com.sun.lwuit.Font;
import com.sun.lwuit.Graphics;
import com.sun.lwuit.Image;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.geom.Dimension;
import com.sun.lwuit.plaf.Style;

//LWUIT doesn't ship with a pre-existing progress indicator, mostly because making something generic enough for all the common cases is not as simple as it might seem in the beginning. Especially when considering how easy it is to write your own progress indicator...
//This is a simple example of how to create a custom component in LWUIT in this specific case a progress indicator that supports both drawing itself (as a filled round rectangle and as a couple of images overlayed one on top of the other. The progress indicator component is fully themeable and customizable and will accept all L&F settings seamlessly.
//The screenshots show both an image based indicator (its ugliness is just a testament to my bad drawing skills) and an indicator drawn in graphics primitives (fill/drawRoundRect). These are the images used to draw the image progress:
//
//As part of this I also wanted to create something else familiar to Swing developers, the SwingWorker. Generally I prefer the foxtrot approach implemented in LWUIT as invokeAndBlock in Display, however lots of people like the SwingWorker approach so I used it here as part of the explanations.
//
//First lets create the Progress indicator component:

/**
* Simple progress indicator component that fills out the progress made.
* Progress is assumed to always be horizontal in this widget
*
* @author Shai Almog
*/
public class Progressbar extends Component {
private byte percent;
private Image unfilled;
private Image filled;

/**
 * The default constructor uses internal rendering to draw the progress
*/
public Progressbar() {
   setFocusable(false);
}

/**
* Allows indicating the progress using a filled/unfilled images.
* The unfilled image is always drawn and the filled image is drawn on top with
* clipping to indicate the amount of progress made.
*
* @param unfilled an image containing the progress bar without any of its
* content being filled (with the progress color)
* @param filled an image identicall to unfilled in every way except that progress
* is completed in this bar.
*/
public Progressbar(Image unfilled, Image filled) {
   this();
   this.unfilled = unfilled;
   this.filled = filled;
}

/**
* Indicate to LWUIT the component name for theming in this case "Progress"
*/
public String getUIID() {
   return "Progress";
}

/**
* Indicates the percent of progress made
*/
public byte getProgress() {
   return percent;
}

/**
* Indicates the percent of progress made, this method is thread safe and
* can be invoked from any thread although discression should still be kept
* so one thread doesn't regress progress made by another thread...
*/
public void setProgress(byte percent) {
   this.percent = percent;
   repaint();
}

/**
* Return the size we would generally like for the component
*/
protected Dimension calcPreferredSize() {
   if(filled != null) {
       return new Dimension(filled.getWidth(), filled.getHeight());
   } else {
       // we don't really need to be in the font height but this provides
       // a generally good indication for size expectations
       return new Dimension(Display.getInstance().getDisplayWidth(),
           Font.getDefaultFont().getHeight());
   }
}

/**
* Paint the progress indicator
*/
public void paint(Graphics g) {
   int width = (int)((((float)percent) / 100.0f) * getWidth());
   if(filled != null) {
       if(filled.getWidth() != getWidth()) {
           filled = filled.scaled(getWidth(), getHeight());
           unfilled = unfilled.scaled(getWidth(), getHeight());
       }
  
       // draw based on two user supplied images
       g.drawImage(unfilled, getX(), getY());
       g.clipRect(getX(), getY(), width, getHeight());
       g.drawImage(filled, getX(), getY());
   } else {
       // draw based on simple graphics primitives
       Style s = getStyle();
       g.setColor(s.getBgColor());
       int curve = getHeight() / 2 - 1;
       g.fillRoundRect(getX(), getY(), getWidth() - 1, getHeight() - 1, curve, curve);
       g.setColor(s.getFgColor());
       g.drawRoundRect(getX(), getY(), getWidth() - 1, getHeight() - 1, curve, curve);
       g.clipRect(getX(), getY(), width - 1, getHeight() - 1);
       g.setColor(s.getBgSelectionColor());
       g.fillRoundRect(getX(), getY(), getWidth() - 1, getHeight() - 1, curve, curve);
   }
}

class ProgressCommand extends Command {
	private Progressbar p;
	public ProgressCommand(String name, Progressbar p) {
	   super(name);
	   this.p = p;
	}
	public void actionPerformed(ActionEvent ev) {
	   new BackgroundTask() {
	       public void performTask() {
	           for(byte b = 0 ; b <= 100 ; b++) {
	               try {
	                   p.setProgress(b);
	                   Thread.sleep(100);
	               } catch (InterruptedException ex) {
	                   ex.printStackTrace();
	               }
	           }
	       }
	   }.start();
	}
	}
}

//This code seems to me to be simple but obviously I'm not objective, if something is not clear or you think it 
//might not be clear to others please let me know in the comments.
//
//BackgroundTask is my equivalent to SwingWorker, its much simpler than SwingWorker:

/**
* A tool allowing to respond to an event in the background possibly with
* progress indication inspired by Swings "SwingWorker" tool. This class
* should be used from event dispatching code to prevent the UI from blocking.
* State can be stored in this class the separate thread and it can be used by
* the finish method which will be invoked after running.
*
* @author Shai Almog
*/
abstract class BackgroundTask {
/**
* Start this task
*/
public final void start() {
   if(Display.getInstance().isEdt()) {
       taskStarted();
   } else {
       Display.getInstance().callSeriallyAndWait(new Runnable() {
           public void run() {
               taskStarted();
           }
       });
   }
   new Thread(new Runnable() {
       public void run() {
           if(Display.getInstance().isEdt()) {
               taskFinished();
           } else {
               performTask();
               Display.getInstance().callSerially(this);
           }
       }
   }).start();
}

/**
* Invoked on the LWUIT EDT before spawning the background thread, this allows
* the developer to perform initialization easily.
*/
public void taskStarted() {
}

/**
* Invoked on a separate thread in the background, this task should not alter
* UI except to indicate progress.
*/
public abstract void performTask();

/**
* Invoked on the LWUIT EDT after the background thread completed its
* execution.
*/
public void taskFinished() {
}
}

//And this is the code to display these two progress bars:
//
//Form progressForm = new Form("Progress");
//progressForm.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
//Progress p1 = new Progress();
//progressForm.addComponent(new Label("Drawn"));
//progressForm.addComponent(p1);
//Progress p2 = new Progress(Image.createImage("/unfilled.png"), Image.createImage("/filled.png"));
//p2.getStyle().setBgTransparency(0);
//progressForm.addComponent(new Label("Image Based"));
//progressForm.addComponent(p2);
//progressForm.show();



//progressForm.addCommand(new ProgressCommand("Drawn", p1));
//progressForm.addCommand(new ProgressCommand("Images", p2));
//
//Posted by Shai Almog at 7:15 AM
//12 comments:
//
//Moshe Lyons said...
//
//    I find that the problem with this code is that it does not go up tick by tick (percent by percent)...it shows 1%,2%,3%,5%,8%,9%....
//    what could be done to improve this?
//    July 30, 2008 12:18 PM 
//Shai Almog said...
//
//    Slow down your application. The progress does go tick by tick it is faster than the speed of painting.
//    July 30, 2008 1:20 PM 
//Moshe Lyons said...
//
//    But this will vary on various devices. (ie. one device maybe able to do more in 100 ms then another device). The behavior needs to be 'speed independant'. Somehow there has got to be a notfiy -> wait conversation with the edt or something...Thread.sleep can have variable results.
//    July 30, 2008 1:38 PM 
//Shai Almog said...
//
//    You can control the application framerate (in Display) but this is not exactly recommended. The general idea of all animations is removing the smoothness for faster devices/applications.
//    If you want pixel perfect progress indication I suggest you use an animation rather than a progress bar since it would have nothing to do with actual progress.
//    July 30, 2008 1:58 PM 
//Abu Mami said...
//
//    Hi Shai, I work with Moshe and I'd like to jump in since the direction the discussion was going really didn't address our problem...
//
//    What we are trying to accomplish can't really be considered animation, rather, we have a background thread that as it completes a task, the UI should be updated.
//
//    To explain further, our thread renders a series of images (small images, such as thumbnails). We would like that each image, as it is completed, will be displayed on the form.
//
//    It seems that some sort of event is needed to notify the UI that the new image is available to be displayed.
//
//    Would appreciate your comments regarding our problem.
//
//    Thanks
//    August 5, 2008 9:53 AM 
//Shai Almog said...
//
//    A call to repaint() is required to update the screen.
//    August 5, 2008 10:16 AM 
//Abu Mami said...
//
//    We have a repaint, and the screen is in fact being updated.
//
//    Our problem is that sometimes 2, sometimes 3, or more, images are updated at one time. We are looking for a smoother update... that is, each time an image has finished being processed, it will be displayed on the screen - one at a time.
//    August 5, 2008 11:02 AM 
//Shai Almog said...
//
//    A. Did you read what I mentioned about framerate. Read the forum http://forums.java.net/jive/forum.jspa?forumID=139&start=0 for actual details. Did you set framerate to 1000.
//
//    B. You need to provide code to reproduce a problem. This is only practical to do in the forum.
//    August 5, 2008 11:16 AM 
//UI Labs said...
//
//    Shai,
//
//    Before I go using this - Do you have any license restrictions with the code posted on your blog?
//
//    Thanks,
//
//    --Bill
//    August 26, 2008 8:26 PM 
//Shai Almog said...
//
//    Hi,
//    All code in this blog unless specifically stated otherwise (so far I didn't state otherwise for anything) is completely free for any use and doesn't require any credit or other restriction.
//    August 26, 2008 8:41 PM 
//UI Labs said...
//
//    Thanks for the clarification Shai.
//
//    --Bill
//    August 26, 2008 8:47 PM 
//info said...
//
//    If I would like to do this the LWUIT way (using invokeAndBlock), how would I do?
//
//    Would it be the same if I change this:
//    public void actionPerformed(ActionEvent ev) {
//    new BackgroundTask() {
//    public void performTask() {
//    for(byte b = 0 ; b <= 100 ; b++) {
//    try {
//    p.setProgress(b);
//    Thread.sleep(100);
//    } catch (InterruptedException ex) {
//    ex.printStackTrace();
//    }
//    }
//    }
//    }.start();
//    }
//
//
//    Into this:
//    public void actionPerformed(ActionEvent ev) {
//    Display.getInstance().invokeAndBlock(new Runnable() {
//    public void run() {
//    for(byte b = 0 ; b <= 100 ; b++) {
//    try {
//    p.setProgress(b);
//    Thread.sleep(100);
//    } catch (InterruptedException ex) {
//    ex.printStackTrace();
//    }
//    }
//    }
//    });
//    }
//    October 10, 2008 1:45 PM 
//
